#include "config.h"
#include "env.h"
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

namespace johnsonli
{
	static johnsonli::Logger::ptr g_logger = LOG_NAME("system");

	//将所有map结构的node都放到 ouput
	//key: A.B value: node
	static void ListAllMember(
		const std::string& prefix,
		const YAML::Node& node,
		std::list<std::pair<std::string, const YAML::Node>>& output)
	{
		if (prefix.find_first_not_of("abcdefghijklmnopqrstuvwxyz._0123456789")
			!= std::string::npos)
		{
			LOG_ERROR(LOG_ROOT()) << "Config invalid name" << prefix;
			return;
		}
		output.push_back(std::make_pair(prefix, node));
		if (node.IsMap())
		{
			for (auto it = node.begin(); it != node.end(); ++it)
			{
				ListAllMember(prefix.empty() ? it->first.Scalar() : prefix + "." + it->first.Scalar(), it->second, output);
			}
		}
	}

	ConfigVarBase::ptr Config::LookupBase(const std::string& name)
	{
		RWMutexType::ReadLock lock(GetMutex());
		auto it = GetDatas().find(name);
		return it == GetDatas().end() ? nullptr : it->second;
	}
	
	static std::map<std::string, uint64_t> s_file2modifytime;
	static johnsonli::Mutex s_mutex;
	//从yaml中加载数据
	void Config::LoadFromYaml(const YAML::Node& root)
	{
		
		std::list<std::pair<std::string, const YAML::Node>> all_nodes;
		ListAllMember("", root, all_nodes);

		for (auto& i : all_nodes)
		{

			std::string key = i.first;
			//std::cout << key << std::endl;
			if (key.empty())
			{
				continue;
			}
			std::transform(key.begin(), key.end(), key.begin(), ::tolower);
			ConfigVarBase::ptr var = LookupBase(key);
			//LOG_INFO(LOG_ROOT()) << "var: " << var->toString();
			if (var)
			{
				if (i.second.IsScalar())
				{
					var->fromString(i.second.Scalar());
				}
				else
				{
					std::stringstream ss;
					ss << i.second;
					var->fromString(ss.str());
				}
			}
		}
	}


	void Config::LoadFromConfDir(const std::string& path, bool force)
	{
		// LOG_INFO(g_logger) << "LoadFromConfDir";
		std::string absoulte_path = johnsonli::EnvMgr::GetInstance()->getAbsolutePath(path);
//		LOG_INFO(g_logger) << absoulte_path;
		std::vector<std::string> files;
		FSUtil::ListAllFile(files, absoulte_path, ".yaml");
//		LOG_INFO(g_logger) << files.size();
		for(auto& i : files)
		{
			// 如果时间没有变化，就不重新加载
			{
				struct stat st;
				lstat(i.c_str(), &st);
				johnsonli::Mutex::Lock lock(s_mutex);
				if(!force && s_file2modifytime[i] == (uint64_t)st.st_mtime) {
					continue;
				}

				s_file2modifytime[i] = st.st_mtime;
			}
			
			try
			{
				YAML::Node root = YAML::LoadFile(i);
				LoadFromYaml(root);
				LOG_INFO(g_logger) << "LoadConfFile file="
					<< i << " ok";
			}
			catch (...)
			{
				LOG_ERROR(g_logger) << "LoadConfFile file="
                	<< i << " failed";
			}

		}
	}
}
